package megrez.bussiness.schedule.web.rest;

import static org.springframework.util.CollectionUtils.isEmpty;
import static org.springframework.util.StringUtils.hasText;

import java.util.Set;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
import megrez.bussiness.schedule.entity.Job;
import megrez.bussiness.schedule.entity.JobLog;
import megrez.bussiness.schedule.entity.JobLog.Level;
import megrez.bussiness.schedule.repository.JobLogRepository;
import megrez.bussiness.schedule.repository.JobLogSpecification;
import megrez.bussiness.schedule.repository.JobRepository;
import megrez.bussiness.schedule.repository.JobSpecification;
import megrez.bussiness.schedule.service.JobService;
import megrez.bussiness.schedule.web.dto.JobDto;
import megrez.bussiness.schedule.web.dto.JobLogDto;
import megrez.bussiness.schedule.web.mapper.JobLogMapper;
import megrez.bussiness.schedule.web.mapper.JobMapper;

/**
 * 任务接口
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@RestController
@RequestMapping("/v1/jobs")
@RequiredArgsConstructor
public class JobResource {
    private final JobRepository jobRepository;
    private final JobLogRepository jobLogRepository;
    private final JobService jobService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public String createJob(@RequestBody JobDto dto) {
        Job entity = jobService.saveJob(JobMapper.INST.toEntity(dto));
        return entity.getId().toString();
    }

    @PutMapping("/{jobId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void updateJob(@PathVariable("jobId") Long id, @RequestBody JobDto dto) {
        jobService.findJobById(id);
        jobService.saveJob(JobMapper.INST.toEntity(dto));
    }

    @DeleteMapping("/{jobId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteJob(@PathVariable("jobId") Long id) {
        jobRepository.deleteById(id);
    }

    @DeleteMapping("/{jobId}/logs")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteJobLog(@PathVariable("jobId") Long id) {
        Job job = jobService.findJobById(id);
        jobLogRepository.deleteByJob(job);
    }

    @GetMapping("/{jobId}")
    public JobDto getById(@PathVariable("jobId") Long id) {
        Job job = jobService.findJobById(id);
        return JobMapper.INST.toDto(job);
    }

    @GetMapping("/page")
    public Page<JobDto> getJobPage(@RequestParam(value = "beanName", required = false) String beanName,
            @RequestParam(value = "enabled", required = false) Boolean enabled,
            @RequestParam(value = "remark", required = false) String remark, Pageable pageable) {
        Specification<Job> where = Specification
                .where(hasText(beanName) ? JobSpecification.beanNameLike(beanName) : null)
                .and(hasText(remark) ? JobSpecification.remarkLike(remark) : null)
                .and(enabled != null ? JobSpecification.enabledEqual(enabled) : null);

        Page<Job> page = jobRepository.findAll(where, pageable);
        return page.map(JobMapper.INST::toDto);
    }

    @GetMapping("/page/logs")
    public Page<JobLogDto> getLogPage(@RequestParam(name = "jobId", required = false) Long jobId,
            @RequestParam(value = "level", required = false) Set<Level> levels, Pageable pageable) {
        Specification<JobLog> where = Specification.where(isEmpty(levels) ? null : JobLogSpecification.levelIn(levels));

        if (jobId != null) {
            Job job = jobService.findJobById(jobId);
            where = where.and(JobLogSpecification.jobEqual(job));
        }

        Page<JobLog> page = jobLogRepository.findAll(where, pageable);
        return page.map(JobLogMapper.INST::toDto);
    }
}
